package org.fireflow2.designer.eclipse.modelwrapper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.fireflow.model.data.Property;
import org.fireflow.model.process.WorkflowElement;
import org.fireflow.pdl.fpdl20.diagram.ActivityShape;
import org.fireflow.pdl.fpdl20.diagram.CommentShape;
import org.fireflow.pdl.fpdl20.diagram.Diagram;
import org.fireflow.pdl.fpdl20.diagram.DiagramElement;
import org.fireflow.pdl.fpdl20.diagram.EndNodeShape;
import org.fireflow.pdl.fpdl20.diagram.Fpdl20DiagramElement;
import org.fireflow.pdl.fpdl20.diagram.GroupShape;
import org.fireflow.pdl.fpdl20.diagram.PoolShape;
import org.fireflow.pdl.fpdl20.diagram.RouterShape;
import org.fireflow.pdl.fpdl20.diagram.StartNodeShape;
import org.fireflow.pdl.fpdl20.diagram.TransitionShape;
import org.fireflow.pdl.fpdl20.diagram.WorkflowNodeShape;
import org.fireflow.pdl.fpdl20.process.Activity;
import org.fireflow.pdl.fpdl20.process.EndNode;
import org.fireflow.pdl.fpdl20.process.Router;
import org.fireflow.pdl.fpdl20.process.StartNode;
import org.fireflow.pdl.fpdl20.process.SubProcess;
import org.fireflow.pdl.fpdl20.process.Transition;
import org.fireflow2.designer.eclipse.modelwrapper.basic.ActivityWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.CommentWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.DataFieldWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.EndNodeWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.GroupWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.PoolWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.ResourceDefWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.RouterWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.ServiceDefWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.StartNodeWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.basic.TransitionWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.ActivityListWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.DataFieldListWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.EndNodeListWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.RouterListWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.StartNodeListWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.TransitionListWrapper;
import org.fireflow2.designer.eclipse.modelwrapper.collection.WorkflowElementListWrapper;

public class SubProcessWrapper extends ModelWrapper{
	StartNodeWrapper startNodeWrapper = null;
	
	/**
	 * SubflowWrapper的直接下级，包含PoolWrapper,CommentWrapper,AssociationWrapper,
	 * MessageFlowWrapper以及流程元素（StartNodeWrapper,ActivityWrapper,TransitionWrapper,EndNodeWrapper,RouterWrapper）。
	 * LaneWrapper包含在PoolWrapper
	 * GroupWrapper中的流程元素不在该列表内。
	 */
	private List<PoolWrapper> poolWrapperList = new  ArrayList<PoolWrapper>();
	private List allNodes4GraphEditor = new ArrayList();
	
	/**
	 * SubflowWrapper中的所有元素
	 */
	private Map<String,Wrapper> sn_modelwrapper_map = new HashMap<String,Wrapper>();
	
	/**
	 * OutlineView中的所有元素
	 */
	private List<Wrapper> allNodes4OutlineView = new ArrayList<Wrapper>();
	private WorkflowElementListWrapper workflowElementListWrapper = new WorkflowElementListWrapper(this);
	private DataFieldListWrapper dataFieldsWrapper = new DataFieldListWrapper();
	private StartNodeListWrapper startNodesWrapper = new StartNodeListWrapper();
	private ActivityListWrapper activitiesWrapper = new ActivityListWrapper();
	private RouterListWrapper routersWrapper = new RouterListWrapper();
	private EndNodeListWrapper endNodesWrapper = new EndNodeListWrapper();
	private TransitionListWrapper transitionsWrapper = new TransitionListWrapper();

	public SubProcessWrapper(SubProcess subflow,DiagramElement diagram,WorkflowProcessWrapper parent){
		super(subflow,diagram);
		this.setParent(parent);
		initChildren();

	}
	
	public List<Wrapper> getAllNodes4GraphEditor() {
		allNodes4GraphEditor.clear();
		allNodes4GraphEditor.addAll(poolWrapperList);
		List<Wrapper> list = this.getChildren();
		for (Wrapper child : list){
			if ((child instanceof DataFieldWrapper) ||
					(child instanceof PoolWrapper) ||
					(child instanceof TransitionWrapper)){
				continue;
			}
			allNodes4GraphEditor.add(child);
		}
		
		return allNodes4GraphEditor;
	}
	public void putToSnModelWrapperMap(String sn,Wrapper wrapp){
		this.sn_modelwrapper_map.put(sn, wrapp);
	}
	
	public void removeFromSnModelWrapperMap(String sn){
		this.sn_modelwrapper_map.remove(sn);
	}
	
	public List getAllNodes4OutlineView() {
		return allNodes4OutlineView;
	}
	
	protected void initChildren(){
		SubProcess subflow = (SubProcess)this.getWorkflowModelElement();
		Diagram diagram = (Diagram)this.getDiagramElement();
		
		sn_modelwrapper_map.put(this.getSn(), this);
		
		this.workflowElementListWrapper.setParent(this);
		this.allNodes4OutlineView.add(((WorkflowProcessWrapper)this.getParent()).getImportListWrapper());
		this.allNodes4OutlineView.add(((WorkflowProcessWrapper)this.getParent()).getServiceListWrapper());
		this.allNodes4OutlineView.add(((WorkflowProcessWrapper)this.getParent()).getResourceListWrapper());
		this.allNodes4OutlineView.add(workflowElementListWrapper);
		
		dataFieldsWrapper.setParent(workflowElementListWrapper);
		startNodesWrapper.setParent(workflowElementListWrapper);
		activitiesWrapper.setParent(workflowElementListWrapper);
		routersWrapper.setParent(workflowElementListWrapper);
		endNodesWrapper.setParent(workflowElementListWrapper);
		transitionsWrapper.setParent(workflowElementListWrapper);
		
		workflowElementListWrapper.addChild(dataFieldsWrapper);
		workflowElementListWrapper.addChild(startNodesWrapper);
		workflowElementListWrapper.addChild(activitiesWrapper);
		workflowElementListWrapper.addChild(routersWrapper);
		workflowElementListWrapper.addChild(endNodesWrapper);
		workflowElementListWrapper.addChild(transitionsWrapper);
		
		
		//TODO datafield 待优化
		List<Property> datafields = subflow.getProperties();		
		for(int i=0;i<datafields.size();i++){
			Property df = (Property)datafields.get(i);
			DataFieldWrapper dfWrapper = new DataFieldWrapper(df);
			
			dfWrapper.setParent(this);
			dataFieldsWrapper.addChild(dfWrapper);
			
			this.sn_modelwrapper_map.put(dfWrapper.getSn(), dfWrapper);
			this.getChildren().add(dfWrapper);
			
		}
			
		List<WorkflowNodeShape> nodeShapeList = diagram.getWorkflowNodeShapes();
		if (nodeShapeList!=null){
			for (WorkflowNodeShape nodeShape : nodeShapeList){
				String wfElmID = nodeShape.getWorkflowElementRef();
				WorkflowElement wfElm = subflow.findWFElementById(wfElmID);
				ModelWrapper modelWrapper = null;
				if (nodeShape instanceof StartNodeShape){
					modelWrapper = new StartNodeWrapper(this,(StartNode)wfElm,nodeShape);
					startNodesWrapper.addChild((StartNodeWrapper)modelWrapper);
				}
				else if (nodeShape instanceof ActivityShape){
					modelWrapper = new ActivityWrapper(this,(Activity)wfElm,nodeShape);
					activitiesWrapper.addChild((ActivityWrapper)modelWrapper);
				}
				else if (nodeShape instanceof RouterShape){
					modelWrapper = new RouterWrapper(this,(Router)wfElm,nodeShape);
					routersWrapper.addChild((RouterWrapper)modelWrapper);
				}
				else if (nodeShape instanceof EndNodeShape){
					modelWrapper = new EndNodeWrapper(this,(EndNode)wfElm,nodeShape);
					endNodesWrapper.addChild((EndNodeWrapper)modelWrapper);
				}
				
				if (modelWrapper!=null){
					modelWrapper.setParent(this);
					
					sn_modelwrapper_map.put(modelWrapper.getSn(), modelWrapper);					
					getChildren().add(modelWrapper);
				}

			}
		}

		//Group
		List<GroupShape> groupShapeList = diagram.getGroups();
		if (groupShapeList!=null){
			for (GroupShape groupShape : groupShapeList){
				//groupwrapper里面存储的是Subflow
				GroupWrapper modelWrapper = new GroupWrapper(this,groupShape);
				
				modelWrapper.setParent(this);
				sn_modelwrapper_map.put(modelWrapper.getSn(), modelWrapper);				
				getChildren().add(modelWrapper);
			}
		}
		
		
		//Pool
		List<PoolShape> poolShapeList = diagram.getPools();
		if (poolShapeList!=null){
			for (PoolShape poolShape : poolShapeList){
				PoolWrapper poolWrapper = new PoolWrapper(this,poolShape);
				poolWrapper.setParent(this);
				sn_modelwrapper_map.put(poolWrapper.getSn(), poolWrapper);				
				this.poolWrapperList.add(poolWrapper);
				this.getChildren().add(poolWrapper);
			}
		}
		
		
		
		//Comment
		List<CommentShape> commentShapeList = diagram.getComments();
		if (commentShapeList!=null){
			for (CommentShape commentShape : commentShapeList){
				CommentWrapper commentWrapper = new CommentWrapper(this,commentShape);
				commentWrapper.setParent(this);
				sn_modelwrapper_map.put(commentWrapper.getSn(), commentWrapper);				
				getChildren().add(commentWrapper);
			}
		}
		
		
		//Transition
		List<TransitionShape> transitionShapeList = diagram.getTransitions();
		if (transitionShapeList!=null){
			for (TransitionShape transShape : transitionShapeList){
				Transition trans = subflow.getTransition(transShape.getWorkflowElementRef());
				TransitionWrapper transWrapper = new TransitionWrapper(this,trans,transShape);

				String fromNodeSN = transShape.getFromWorkflowNodeShape()==null?"":transShape.getFromWorkflowNodeShape().getId();
				String toNodeSN = transShape.getToWorkflowNodeShape()==null?"":transShape.getToWorkflowNodeShape().getId();
				NodeWrapper source = (NodeWrapper)sn_modelwrapper_map.get(fromNodeSN);
				NodeWrapper target = (NodeWrapper)sn_modelwrapper_map.get(toNodeSN);
				if (source!=null) {
					source.setLeavingTransition(transWrapper);
					transWrapper.setSource(source);
				}
				if (target!=null){
					target.setEnteringTransition(transWrapper);
					transWrapper.setTarget(target);
				}

				transWrapper.setParent(this);				
				sn_modelwrapper_map.put(transWrapper.getSn(), transWrapper);				
				this.getChildren().add(transWrapper);
				transitionsWrapper.addChild(transWrapper);
			}
		}
		
		//
		
		//Association
		
		//MessageFlow
	}
	
	public void orphanChild(Wrapper child){
		if (!(child instanceof NodeWrapper)) return;
		
		Diagram diagram = (Diagram)this.getDiagramElement();
		if (child instanceof GroupWrapper){
			diagram.getGroups().remove(((NodeWrapper)child).getDiagramElement());
		}
		else if (child instanceof StartNodeWrapper ||
				child instanceof EndNodeWrapper ||
				child instanceof RouterWrapper ||
				child instanceof ActivityWrapper){
			diagram.getWorkflowNodeShapes().remove(((NodeWrapper)child).getDiagramElement());
		}
		else if (child instanceof CommentWrapper){
			diagram.getComments().remove(((NodeWrapper)child).getDiagramElement());
		}
		super.orphanChild(child);
	}
	
	public void acceptChild(Wrapper wrapper){
		if (!(wrapper instanceof NodeWrapper))return;
		NodeWrapper child = (NodeWrapper)wrapper;
		wrapper.setParent(this);
		Diagram diagram = (Diagram)this.getDiagramElement();
		if (child instanceof GroupWrapper){
			diagram.addGroup((GroupShape)child.getDiagramElement());
		}
		else if (child instanceof StartNodeWrapper ||
				child instanceof EndNodeWrapper ||
				child instanceof RouterWrapper ||
				child instanceof ActivityWrapper){
			diagram.addWorkflowNodeShape((WorkflowNodeShape)child.getDiagramElement());
		}
		else if (child instanceof CommentWrapper){
			diagram.addComment((CommentShape)child.getDiagramElement());
		}
		
		this.addChild(child,-1);
	}


	public int deleteChild(Wrapper wrapperToBeDeleted){
		if (wrapperToBeDeleted instanceof TransitionWrapper){
			//特别主意：transitionWrapper不需要加入到this.children列表中，
			//所以此处无super.deleteChild(wrapperToBeDeleted);
			this.deleteTransitionWrapper((TransitionWrapper)wrapperToBeDeleted);

		}else if ((wrapperToBeDeleted instanceof ActivityWrapper) 
					||(wrapperToBeDeleted instanceof RouterWrapper)
					||(wrapperToBeDeleted instanceof StartNodeWrapper)
					||( wrapperToBeDeleted instanceof EndNodeWrapper)){
			deleteWorkflowNodeWrapper((NodeWrapper)wrapperToBeDeleted);
			
		}else if (wrapperToBeDeleted instanceof PoolWrapper){
//			deletePoolWrapper((PoolWrapper)wrapperToBeDeleted);
			
		}else if (wrapperToBeDeleted instanceof GroupWrapper){
			//TODO delete Group wrapper
		}else if (wrapperToBeDeleted instanceof ServiceDefWrapper){
			//交给WorkflowProcessWrapper处理
			return this.getParent().deleteChild(wrapperToBeDeleted);
		}
		else if (wrapperToBeDeleted instanceof ResourceDefWrapper){
			//交给WorkflowProcessWrapper处理
			return this.getParent().deleteChild(wrapperToBeDeleted);
		}
		else if (wrapperToBeDeleted instanceof DataFieldWrapper){
			this.deleteDataFieldWrapper((DataFieldWrapper)wrapperToBeDeleted);

		}
		return super.deleteChild(wrapperToBeDeleted);
	}
	protected void deleteWorkflowNodeWrapper(NodeWrapper nodeWrapper){
		SubProcess subflow = (SubProcess)this.getWorkflowModelElement();
		Diagram diagram = (Diagram)this.getDiagramElement();
		
		nodeWrapper.setParent(null);
		sn_modelwrapper_map.remove(nodeWrapper.getSn());
		
		if (nodeWrapper instanceof StartNodeWrapper){		
			this.startNodesWrapper.deleteChild((StartNodeWrapper)nodeWrapper);
			subflow.getStartNodes().remove((StartNode)nodeWrapper.getWorkflowModelElement());
		}
		else if (nodeWrapper instanceof ActivityWrapper){
			activitiesWrapper.deleteChild((ActivityWrapper)nodeWrapper);
			subflow.getActivities().remove((Activity)nodeWrapper.getWorkflowModelElement());
		}
		else if (nodeWrapper instanceof EndNodeWrapper){
			endNodesWrapper.deleteChild((EndNodeWrapper)nodeWrapper);
			subflow.getEndNodes().remove((EndNode)nodeWrapper.getWorkflowModelElement());
		}		
		else if (nodeWrapper instanceof RouterWrapper){
			routersWrapper.deleteChild((RouterWrapper)nodeWrapper);
			subflow.getRouters().remove((Router)nodeWrapper.getWorkflowModelElement());
		}
		
		diagram.getWorkflowNodeShapes().remove((WorkflowNodeShape)nodeWrapper.getDiagramElement());
	}
	

	public void addChild(Wrapper wrapperToBeAdded,int index){
		if (wrapperToBeAdded instanceof TransitionWrapper){
			this.addTransitionWrapper((TransitionWrapper)wrapperToBeAdded);
			super.addChild(wrapperToBeAdded, index);
		}else if ((wrapperToBeAdded instanceof ActivityWrapper) 
					||(wrapperToBeAdded instanceof RouterWrapper)
					||(wrapperToBeAdded instanceof StartNodeWrapper)
					||( wrapperToBeAdded instanceof EndNodeWrapper)){
			addWorkflowNodeWrapper((NodeWrapper)wrapperToBeAdded);
			super.addChild(wrapperToBeAdded, index);
		}else if (wrapperToBeAdded instanceof PoolWrapper){
			addPoolWrapper((PoolWrapper)wrapperToBeAdded);
			super.addChild(wrapperToBeAdded, index);
		}else if (wrapperToBeAdded instanceof GroupWrapper){
			addGroupWrapper((GroupWrapper)wrapperToBeAdded);
			super.addChild(wrapperToBeAdded, index);
		}else if (wrapperToBeAdded instanceof ServiceDefWrapper){
			//交给WorkflowProcessWrapper处理，使之能够加入到模型中
			this.getParent().addChild(wrapperToBeAdded, index);
		}
		else if (wrapperToBeAdded instanceof ResourceDefWrapper){
			this.getParent().addChild(wrapperToBeAdded, index);
		}
		else if (wrapperToBeAdded instanceof DataFieldWrapper){
			this.addDataFieldWrapper((DataFieldWrapper)wrapperToBeAdded);
			super.addChild(wrapperToBeAdded, index);
		}
	}

	
	protected void addGroupWrapper(GroupWrapper groupWrapper){
		Diagram diagram = (Diagram)this.getDiagramElement();
		
		groupWrapper.setParent(this);
		
		diagram.addGroup((GroupShape)groupWrapper.getDiagramElement());
		
		this.sn_modelwrapper_map.put(groupWrapper.getSn(), groupWrapper);
	}
	
	
	protected void addPoolWrapper(PoolWrapper poolWrapper){
		Diagram diagram = (Diagram)this.getDiagramElement();
		
		poolWrapper.setParent(this);
		poolWrapperList.add(poolWrapper);
		this.sn_modelwrapper_map.put(poolWrapper.getSn(), poolWrapper);
		diagram.addPool((PoolShape)poolWrapper.getDiagramElement());
	}
	
	/**
	 * 添加流程节点元素（不包含Pool,Comment,Group,Comment）
	 * @param nodeWrapper
	 * @param parentWrapper
	 */
	protected void addWorkflowNodeWrapper(NodeWrapper nodeWrapper){
		SubProcess subflow = (SubProcess)this.getWorkflowModelElement();
		Diagram diagram = (Diagram)this.getDiagramElement();
		
		//1、构造上下级关系		
		nodeWrapper.setParent(this);		
		sn_modelwrapper_map.put(nodeWrapper.getSn(), nodeWrapper);
	
		//2、将流程元素和图形元素加入到流程模型中
		if (nodeWrapper instanceof StartNodeWrapper){
			subflow.getStartNodes().add((StartNode)nodeWrapper.getWorkflowModelElement());
			diagram.getWorkflowNodeShapes().add((WorkflowNodeShape)nodeWrapper.getDiagramElement());
			this.startNodesWrapper.addChild((StartNodeWrapper)nodeWrapper);
		}else if (nodeWrapper instanceof ActivityWrapper){
			subflow.getActivities().add((Activity)nodeWrapper.getWorkflowModelElement());
			
			diagram.getWorkflowNodeShapes().add((WorkflowNodeShape)nodeWrapper.getDiagramElement());
			activitiesWrapper.addChild((ActivityWrapper)nodeWrapper);
		}
		else if (nodeWrapper instanceof EndNodeWrapper){
			subflow.getEndNodes().add((EndNode)nodeWrapper.getWorkflowModelElement());
			diagram.getWorkflowNodeShapes().add((WorkflowNodeShape)nodeWrapper.getDiagramElement());
			endNodesWrapper.addChild((EndNodeWrapper)nodeWrapper);
		}		
		else if (nodeWrapper instanceof RouterWrapper){
			subflow.getRouters().add((Router)nodeWrapper.getWorkflowModelElement());
			
			diagram.getWorkflowNodeShapes().add((WorkflowNodeShape)nodeWrapper.getDiagramElement());
			routersWrapper.addChild((RouterWrapper)nodeWrapper);
		}
	}
	
	
	protected void deleteTransitionWrapper(TransitionWrapper transWrapper){
		SubProcess subflow = (SubProcess)this.getWorkflowModelElement();
		Diagram diagram = (Diagram)this.getDiagramElement();
		
		transWrapper.setParent(null);

		sn_modelwrapper_map.remove(transWrapper.getSn());
		this.transitionsWrapper.deleteChild(transWrapper);	
		
		//从流程模型中删除
		subflow.getTransitions().remove((Transition)transWrapper.getWorkflowModelElement());
		diagram.getTransitions().remove((TransitionShape)transWrapper.getDiagramElement());
		
	}
	
	
	protected void addTransitionWrapper(TransitionWrapper transWrapper){
		SubProcess subflow = (SubProcess)this.getWorkflowModelElement();
		Diagram diagram = (Diagram)this.getDiagramElement();

		transWrapper.setParent(this);

		this.transitionsWrapper.addChild(transWrapper);	
		sn_modelwrapper_map.put(transWrapper.getSn(),transWrapper);

		
		subflow.getTransitions().add((Transition)transWrapper.getWorkflowModelElement());
		diagram.getTransitions().add((TransitionShape)transWrapper.getDiagramElement());
		
		this.fireStructureChange(transWrapper.getElementType(), transWrapper);
	}
	
	protected void addDataFieldWrapper(DataFieldWrapper dfWrapper){
		dfWrapper.setParent(this);
		
		SubProcess subProcess = (SubProcess)this.getWorkflowModelElement();
		subProcess.getProperties().add((Property)dfWrapper.getWorkflowModelElement());
		
		this.sn_modelwrapper_map.put(dfWrapper.getSn(), dfWrapper);
		this.dataFieldsWrapper.addChild(dfWrapper);
		
	}
	
	protected void deleteDataFieldWrapper(DataFieldWrapper dfWrapper){
		dfWrapper.setParent(null);
		SubProcess subProcess = (SubProcess)this.getWorkflowModelElement();
		subProcess.getProperties().remove((Property)dfWrapper.getWorkflowModelElement());
		this.sn_modelwrapper_map.remove(dfWrapper.getSn());
		this.dataFieldsWrapper.deleteChild(dfWrapper);
		
	}

	public AbsWrapper findModelWrapperBySn(String sn){
		return (AbsWrapper)this.sn_modelwrapper_map.get(sn);
	}
	public DataFieldListWrapper getDataFieldsWrapper(){
		return this.dataFieldsWrapper;
	}
	public ActivityListWrapper getActivitiesWrapper(){
		return this.activitiesWrapper;
	}
	
	public RouterListWrapper getRoutersWrapper(){
		return this.routersWrapper;
	}
	
	public StartNodeListWrapper getStartNodesWrapper(){
		return this.startNodesWrapper;
	}
	
	public EndNodeListWrapper getEndNodesWrapper(){
		return this.endNodesWrapper;
	}
	
	public  String getElementType(){
		return Fpdl20DiagramElement.SUBFLOW.name();
	}		
}
